package com.goldsprite.simplexnoise;

import java.util.Random;

public class SimplexNoise1D {
    public static void main(String[] args) {
        SimplexNoise simplexNoise = new SimplexNoise(0.07, new Random().nextInt()); // scale 改为 0.08
        int width = 100; // 横向打印的点数

        // 统计变量
        double minNoise = Double.MAX_VALUE;
        double maxNoise = Double.MIN_VALUE;
        double totalNoise = 0;
        int[] distribution = new int[10]; // 分为10个区间统计分布

        for (int x = 0; x < width; x++) {
            double noiseValue = simplexNoise.noise(x * simplexNoise.scale);

            // 更新统计数据
            minNoise = Math.min(minNoise, noiseValue);
            maxNoise = Math.max(maxNoise, noiseValue);
            totalNoise += noiseValue;

            // 统计分布
            int index = (int) ((noiseValue + 1) / 2 * (distribution.length - 1));
            distribution[Math.max(0, Math.min(distribution.length - 1, index))]++;

            // 打印条形图
            String bar = getBarFromNoise(noiseValue);
            System.out.println(bar);
        }

        // 打印统计结果
        System.out.println("\n--- Noise Statistics ---");
        System.out.println("Min Noise: " + minNoise);
        System.out.println("Max Noise: " + maxNoise);
        System.out.println("Average Noise: " + (totalNoise / width));

        // 打印分布的条状图
        System.out.println("\nDistribution:");
        for (int i = 0; i < distribution.length; i++) {
            double rangeStart = -1 + (2.0 * i / distribution.length);
            double rangeEnd = rangeStart + 2.0 / distribution.length;
			String bar = new String(new char[distribution[i] / 2]).replace("\0", "#");// 使用分布数量绘制条状图
            System.out.printf("[% .2f, % .2f): %s (%d)\n", rangeStart, rangeEnd, bar, distribution[i]);
        }
    }

    /**
     * 将噪声值映射为字符长度的条形
     */
    private static String getBarFromNoise(double noise) {
        int maxBarLength = 50; // 条形的最大长度
        int barLength = (int) ((noise + 1) / 2 * maxBarLength); // 噪声映射到 [0, maxBarLength]

		return new String(new char[Math.max(1, barLength)]).replace("\0", "#");// 至少打印 1 个字符
    }

    static class SimplexNoise {
        private final double scale;
        private final int seed;

        public SimplexNoise(double scale, int seed) {
            this.scale = scale;
            this.seed = seed;
        }

        public double noise(double x) {
            int i0 = fastFloor(x);
            int i1 = i0 + 1;
            double x0 = x - i0;
            double x1 = x0 - 1.0;

            double n0 = gradient(hash(i0 + seed), x0);
            double n1 = gradient(hash(i1 + seed), x1);

            double t0 = 1.0 - x0 * x0;
            t0 *= t0;
            n0 *= t0 * t0;

            double t1 = 1.0 - x1 * x1;
            t1 *= t1;
            n1 *= t1 * t1;

            return 0.395 * (n0 + n1);
        }

        private int fastFloor(double x) {
            return x > 0 ? (int) x : (int) x - 1;
        }

        private double gradient(int hash, double x) {
            int h = hash & 15;
            double grad = 1.0 + (h & 7);
            if ((h & 8) != 0) grad = -grad;
            return grad * x;
        }

        private int hash(int x) {
            x = (x << 13) ^ x;
            return (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff;
        }
    }
}

